home *** CD-ROM | disk | FTP | other *** search
/ Programmer Power Tools / Programmer Power Tools.iso / editor / j414src.arc / IO.C < prev    next >
C/C++ Source or Header  |  1989-10-10  |  31KB  |  1,490 lines

  1. /***************************************************************************
  2.  * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
  3.  * is provided to you without charge, and with no warranty.  You may give  *
  4.  * away copies of JOVE, including sources, provided that this notice is    *
  5.  * included in all the files.                                              *
  6.  ***************************************************************************/
  7.  
  8. #include "jove.h"
  9. #include "list.h"
  10. #include "fp.h"
  11. #include "termcap.h"
  12. #include "ctype.h"
  13. #include "disp.h"
  14. #include "scandir.h"
  15.  
  16.  
  17. #ifdef IPROCS
  18. # include <signal.h>
  19. #endif
  20.  
  21. #ifdef MAC
  22. # include "mac.h"
  23. #else
  24. # include <sys/stat.h>
  25. #endif
  26.  
  27. #ifdef UNIX
  28. # include <sys/file.h>
  29. #endif
  30.  
  31. #ifdef MSDOS
  32. # include <fcntl.h>
  33. # include <io.h>
  34. # include <direct.h>
  35. # include <dos.h>
  36. #endif /* MSDOS */
  37.  
  38. #include <errno.h>
  39.  
  40. private struct block
  41.     *b_unlink proto((struct block *)),
  42.     *lookup proto((/*int*/short));
  43.  
  44. private char
  45.     *dbackup proto((char *, char *, int)),
  46. #if defined(MSDOS)
  47.     *fixpath proto((char *)),
  48. #endif
  49.     *getblock proto((daddr, int));
  50.  
  51. private void
  52. #if defined(MSDOS)
  53.     abspath proto((char *, char *)),
  54. #endif
  55.     fake_blkio proto((struct block *, int (*)())),
  56.     DoWriteReg proto((int app)),
  57.     LRUunlink proto((struct block *)),
  58.     file_backup proto((char *fname)),
  59.     real_blkio proto((struct block *, int (*)())),
  60.     dfollow proto((char *, char *));
  61.  
  62. #if defined(MSDOS)
  63. private int
  64.     Dchdir proto((char *));
  65. #endif
  66.  
  67. #ifndef W_OK
  68. # define W_OK    2
  69. # define F_OK    0
  70. #endif
  71.  
  72. #define    READ    0
  73. #define    WRITE    1    /* block operation read or write */
  74.  
  75. long    io_chars;        /* number of chars in this open_file */
  76. int    io_lines;        /* number of lines in this open_file */
  77.  
  78. #if defined(VMUNIX) || defined(MSDOS)
  79. char    iobuff[LBSIZE],
  80.     genbuf[LBSIZE],
  81.     linebuf[LBSIZE];
  82. #else
  83. char    *iobuff,
  84.     *genbuf,
  85.     *linebuf;
  86. #endif
  87.  
  88. #ifdef BACKUPFILES
  89. int    BkupOnWrite = 0;
  90. #endif
  91.  
  92. void
  93. close_file(fp)
  94. File    *fp;
  95. {
  96.     if (fp) {
  97.         if (fp->f_flags & F_TELLALL)
  98.             add_mess(" %d lines, %D characters.",
  99.                  io_lines,
  100.                  io_chars);
  101.         f_close(fp);
  102.     }
  103. }
  104.  
  105. /* Write the region from line1/char1 to line2/char2 to FP.  This
  106.    never CLOSES the file since we don't know if we want to. */
  107.  
  108. int    EndWNewline = 1;
  109.  
  110. void
  111. putreg(fp, line1, char1, line2, char2, makesure)
  112. register File    *fp;
  113. Line    *line1,
  114.     *line2;
  115. int    char1,
  116.     char2,
  117.     makesure;
  118. {
  119.     register int    c;
  120.     register char    *lp;
  121.  
  122.     if (makesure)
  123.         (void) fixorder(&line1, &char1, &line2, &char2);
  124.     while (line1 != line2->l_next) {
  125.         lp = lcontents(line1) + char1;
  126.         if (line1 == line2) {
  127.             fputnchar(lp, (char2 - char1), fp);
  128.             io_chars += (char2 - char1);
  129.         } else {
  130.             while ((c = *lp++) != '\0') {
  131.                 jputc(c, fp);
  132.                 io_chars += 1;
  133.             }
  134.         }
  135.         if (line1 != line2) {
  136.             io_lines += 1;
  137.             io_chars += 1;
  138. #ifdef MSDOS
  139.             jputc('\r', fp);
  140. #endif /* MSDOS */
  141.             jputc('\n', fp);
  142.         }
  143.         line1 = line1->l_next;
  144.         char1 = 0;
  145.     }
  146.     flush(fp);
  147. }
  148.  
  149. private void
  150. dofread(fp)
  151. register File    *fp;
  152. {
  153.     char    end[LBSIZE];
  154.     int    xeof = 0;
  155.     Line    *savel = curline;
  156.     int    savec = curchar;
  157.  
  158.     strcpy(end, linebuf + curchar);
  159.     xeof = f_gets(fp, linebuf + curchar, (size_t) (LBSIZE - curchar));
  160.     SavLine(curline, linebuf);
  161.     if (!xeof) do {
  162.         curline = listput(curbuf, curline);
  163.         xeof = f_getputl(curline, fp);
  164.     } while (!xeof);
  165.     getDOT();
  166.     linecopy(linebuf, (curchar = strlen(linebuf)), end);
  167.     SavLine(curline, linebuf);
  168.     IFixMarks(savel, savec, curline, curchar);
  169. }
  170.  
  171. void
  172. read_file(file, is_insert)
  173. char    *file;
  174. int    is_insert;
  175. {
  176.     Bufpos    save;
  177.     File    *fp;
  178.  
  179.     if (is_insert == NO)
  180.         curbuf->b_ntbf = NO;
  181.     fp = open_file(file, iobuff, F_READ, NO, NO);
  182.     if (fp == NIL) {
  183.         if (!is_insert && errno == ENOENT)
  184.             s_mess("(new file)");
  185.         else
  186.             s_mess(IOerr("open", file));
  187.         return;
  188.     }
  189.     if (is_insert == NO) {
  190.         set_ino(curbuf);
  191.         if (fp->f_flags & F_READONLY) {
  192.             set_arg_value(1);
  193.         } else {
  194.             set_arg_value(0);
  195.         }
  196.         TogMinor(ReadOnly);
  197.     }
  198.  
  199.     DOTsave(&save);
  200.     dofread(fp);
  201.     if (is_insert && io_chars > 0) {
  202.         modify();
  203.         set_mark();
  204.     }
  205.     SetDot(&save);
  206.     getDOT();
  207.     close_file(fp);
  208. }
  209.  
  210. void
  211. SaveFile()
  212. {
  213.     if (IsModified(curbuf)) {
  214.         if (curbuf->b_fname == 0)
  215.             WriteFile();
  216.         else {
  217.             filemunge(curbuf->b_fname);
  218. #if !defined(MAC) && !defined(MSDOS)
  219.             chk_mtime(curbuf, curbuf->b_fname, "save");
  220. #endif
  221.             file_write(curbuf->b_fname, 0);
  222.         }
  223.     } else
  224.         message("No changes need to be written.");
  225. }
  226.  
  227. char    *HomeDir;    /* home directory */
  228. size_t    HomeLen;    /* length of home directory string */
  229.  
  230. private List        *DirStack = 0;
  231. #define dir_name(dp)    ((char *) list_data((dp)))
  232. #define PWD_PTR        (list_data(DirStack))
  233. #define PWD        ((char *) PWD_PTR)
  234.  
  235. char *
  236. pwd()
  237. {
  238.     return (char *) PWD_PTR;
  239. }
  240.  
  241. char *
  242. pr_name(fname, okay_home)
  243. char    *fname;
  244. int    okay_home;
  245. {
  246.     int    n;
  247.  
  248.     if (fname == 0)
  249.         return 0;
  250.     n = numcomp(fname, PWD);
  251.  
  252.     if ((PWD[n] == 0) &&    /* Matched to end of PWD */
  253.         (fname[n] == '/'))
  254.         return fname + n + 1;
  255.  
  256.     if (okay_home && strcmp(HomeDir, "/") != 0 &&
  257.         strncmp(fname, HomeDir, HomeLen) == 0 &&
  258.         fname[HomeLen] == '/') {
  259.         static char    name_buf[100];
  260.  
  261.         swritef(name_buf, "~%s", fname + HomeLen);
  262.         return name_buf;
  263.     }
  264.  
  265.     return fname;    /* return entire path name */
  266. }
  267.  
  268. #ifdef    MSDOS
  269. extern unsigned int fmask;
  270. #endif    /* MSDOS */
  271.  
  272. void
  273. Chdir()
  274. {
  275.     char    dirbuf[FILESIZE];
  276.  
  277. #ifdef MSDOS
  278.     fmask = 0x10;
  279. #endif
  280.     (void) ask_file((char *) 0, PWD, dirbuf);
  281. #ifdef MSDOS
  282.     fmask = 0x13;
  283.     if (Dchdir(dirbuf) == -1)
  284. #else
  285.     if (chdir(dirbuf) == -1)
  286. #endif
  287.     {
  288.         s_mess("cd: cannot change into %s.", dirbuf);
  289.         return;
  290.     }
  291.     UpdModLine = YES;
  292.     setCWD(dirbuf);
  293.     prCWD();
  294. #ifdef MAC
  295.     Bufchange++;
  296. #endif
  297. }
  298.  
  299. #if defined(UNIX)
  300.  
  301. #  if !defined(BSD4_2)
  302. char *
  303. getwd(buffer)
  304. char    *buffer;
  305. {
  306.     Buffer    *old = curbuf;
  307.     char    *ret_val;
  308.  
  309.     SetBuf(do_select((Window *) 0, "pwd-output"));
  310.     curbuf->b_type = B_PROCESS;
  311.     (void) UnixToBuf("pwd-output", NO, 0, YES, "/bin/pwd", (char *) 0);
  312.     ToFirst();
  313.     strcpy(buffer, linebuf);
  314.     SetBuf(old);
  315.     return buffer;
  316. }
  317. #  endif    /* not BSD4_2 */
  318.  
  319. /* Check if dn is the name of the current working directory
  320.    and that it is in cannonical form */
  321.  
  322. int
  323. chkCWD(dn)
  324. char    *dn;
  325. {
  326.     char    filebuf[FILESIZE];
  327.     struct stat    dnstat,
  328.             dotstat;
  329.  
  330.     if (dn[0] != '/')
  331.         return FALSE;        /* need absolute pathname */
  332.     PathParse(dn, filebuf);
  333.     return stat(filebuf, &dnstat) == 0 &&
  334.            stat(".", &dotstat) == 0 &&
  335.            dnstat.st_dev == dotstat.st_dev &&
  336.            dnstat.st_ino == dotstat.st_ino;
  337. }
  338.  
  339. #endif /* UNIX */
  340.  
  341. void
  342. setCWD(d)
  343. char    *d;
  344. {
  345.     if (DirStack == NIL)
  346.         list_push(&DirStack, (Element *) 0);
  347.     if (PWD == 0)
  348.         PWD_PTR = (Element *) emalloc((size_t) (strlen(d) + 1));
  349.     else
  350.         PWD_PTR = (Element *) ralloc(PWD, strlen(d) + 1);
  351.     strcpy(PWD, d);
  352. }
  353.  
  354. void
  355. getCWD()
  356. {
  357.     char    *cwd;
  358.     char    pathname[FILESIZE];
  359. #if defined(UNIX) && defined(JOB_CONTROL)
  360.     extern char    *getwd();
  361. #endif
  362. #if defined(MSDOS)
  363.     extern char    *getcwd();
  364. #endif
  365.  
  366. #ifndef MSDOS
  367.     cwd = getenv("CWD");
  368.     if (cwd == 0 || !chkCWD(cwd)) {
  369.         cwd = getenv("PWD");
  370.         if (cwd == 0 || !chkCWD(cwd))
  371.             cwd = getwd(pathname);
  372.     }
  373. #else /* MSDOS */
  374.         cwd = fixpath(getcwd(pathname, FILESIZE));
  375. #endif /* MSDOS */
  376.     setCWD(cwd);
  377. }
  378.  
  379. void
  380. prDIRS()
  381. {
  382.     register List    *lp;
  383.  
  384.     s_mess(": %f ");
  385.     for (lp = DirStack; lp != NIL; lp = list_next(lp))
  386.         add_mess("%s ", pr_name(dir_name(lp), YES));
  387. }
  388.  
  389. void
  390. prCWD()
  391. {
  392.     s_mess(": %f => \"%s\"", PWD);
  393. }
  394.  
  395. void
  396. Pushd()
  397. {
  398.     char    *newdir,
  399.         dirbuf[FILESIZE];
  400.  
  401. #ifdef MSDOS
  402.     fmask = 0x10;
  403. #endif
  404.     newdir = ask_file((char *) 0, NullStr, dirbuf);
  405. #ifdef MSDOS
  406.     fmask = 0x13;
  407. #endif
  408.     UpdModLine = YES;
  409.     if (*newdir == 0) {    /* Wants to swap top two entries */
  410.         char    *old_top;
  411.  
  412.         if (list_next(DirStack) == NIL)
  413.             complain("pushd: no other directory.");
  414.         old_top = PWD;
  415.         list_data(DirStack) = (Element *) dir_name(list_next(DirStack));
  416.         list_data(list_next(DirStack)) = (Element *) old_top;
  417. #ifdef MSDOS
  418.         (void) Dchdir(PWD);
  419. #else
  420.         (void) chdir(PWD);
  421. #endif
  422.     } else {
  423. #ifdef MSDOS
  424.         if (Dchdir(dirbuf) == -1)
  425. #else
  426.         if (chdir(dirbuf) == -1)
  427. #endif
  428.         {
  429.             s_mess("pushd: cannot change into %s.", dirbuf);
  430.             return;
  431.         }
  432.         (void) list_push(&DirStack, (Element *) 0);
  433.         setCWD(dirbuf);
  434.     }
  435.     prDIRS();
  436. }
  437.  
  438. void
  439. Popd()
  440. {
  441.     if (list_next(DirStack) == NIL)
  442.         complain("popd: directory stack is empty.");
  443.     UpdModLine = YES;
  444.     free((char *) list_pop(&DirStack));
  445. #ifdef MSDOS
  446.     (void) Dchdir(PWD);    /* If this doesn't work, we's in deep shit. */
  447. #else
  448.     (void) chdir(PWD);    /* If this doesn't work, we's in deep shit. */
  449. #endif
  450.     prDIRS();
  451. }
  452.  
  453. private char *
  454. dbackup(base, offset, c)
  455. register char    *base,
  456.         *offset;
  457. register int    c;
  458. {
  459.     while (offset > base && *--offset != c)
  460.         ;
  461.     return offset;
  462. }
  463.  
  464. private void
  465. dfollow(file, into)
  466. char    *file,
  467.     *into;
  468. {
  469.     char    *dp,
  470. #ifdef MSDOS
  471.         filefix[FILESIZE],
  472. #endif
  473.         *sp;
  474.  
  475. #ifndef MSDOS
  476.     if (*file == '/') {        /* Absolute pathname */
  477.         strcpy(into, "/");
  478.         file += 1;
  479.     } else
  480.         strcpy(into, PWD);
  481. #else
  482.     abspath(file, filefix);        /* convert to absolute pathname */
  483.     strcpy(into, filefix);        /* and forget about drives    */
  484.     into[3] = 0;
  485.     into = &(into[2]);
  486.     file = &(filefix[3]);
  487. #endif
  488.     dp = into + strlen(into);
  489.  
  490.     sp = file;
  491.     do {
  492.         if (*file == 0)
  493.             break;
  494.         if ((sp = strchr(file, '/')) != '\0')
  495.             *sp = 0;
  496.         if (strcmp(file, ".") == 0)
  497.             ;    /* So it will get to the end of the loop */
  498.         else if (strcmp(file, "..") == 0) {
  499.             *(dp = dbackup(into, dp, '/')) = 0;
  500.             if (dp == into)
  501.                 strcpy(into, "/"), dp = into + 1;
  502.         } else {
  503.             if (into[strlen(into) - 1] != '/')
  504.                 (void) strcat(into, "/"), dp += 1;
  505.             (void) strcat(into, file);
  506.             dp += strlen(file);    /* stay at the end */
  507.         }
  508.         file = sp + 1;
  509.     } while (sp != 0);
  510. }
  511.  
  512. #if defined(UNIX)
  513.  
  514. # if defined(YP_PASSWD)
  515.  
  516. #include <pwd.h>
  517.  
  518. private void
  519. get_hdir(user, buf)
  520. register char    *user,
  521.         *buf;
  522. {
  523.     struct passwd    *p;
  524.  
  525.     p = getpwnam(user);
  526.     endpwent();
  527.     if (p == NULL) {
  528.         add_mess(" [unknown user: %s]", user);
  529.         SitFor(7);
  530.         complain((char *) 0);
  531.         /* NOTREACHED */
  532.     }
  533.     strcpy(buf, p->pw_dir);
  534. }
  535.  
  536. #else
  537.  
  538. private
  539. get_hdir(user, buf)
  540. register char    *user,
  541.         *buf;
  542. {
  543.     char    fbuf[LBSIZE],
  544.         pattern[100];
  545.     register int    u_len;
  546.     File    *fp;
  547.  
  548.     u_len = strlen(user);
  549.     fp = open_file("/etc/passwd", fbuf, F_READ, YES, YES);
  550.     swritef(pattern, "%s:[^:]*:[^:]*:[^:]*:[^:]*:\\([^:]*\\):", user);
  551.     while (f_gets(fp, genbuf, LBSIZE) != EOF)
  552.         if ((strncmp(genbuf, user, u_len) == 0) &&
  553.             (LookingAt(pattern, genbuf, 0))) {
  554.             putmatch(1, buf, FILESIZE);
  555.             close_file(fp);
  556.             return;
  557.         }
  558.     close_file(fp);
  559.     add_mess(" [unknown user: %s]", user);
  560.     SitFor(7);
  561.     complain((char *) 0);
  562. }
  563.  
  564. #endif /* YP_PASSWD */
  565. #endif /* UNIX */
  566.  
  567. void
  568. PathParse(name, intobuf)
  569. char    *name,
  570.     *intobuf;
  571. {
  572.     char    localbuf[FILESIZE];
  573.  
  574.     intobuf[0] = localbuf[0] = '\0';
  575.     if (*name == '\0')
  576.         return;
  577.     if (*name == '~') {
  578.         if (name[1] == '/' || name[1] == '\0') {
  579.             strcpy(localbuf, HomeDir);
  580.             name += 1;
  581.         }
  582. #if !(defined(MSDOS) || defined(MAC))    /* may add for mac in future */
  583.         else {
  584.             char    *uendp = strchr(name, '/'),
  585.                 unamebuf[30];
  586.  
  587.             if (uendp == 0)
  588.                 uendp = name + strlen(name);
  589.             name += 1;
  590.             null_ncpy(unamebuf, name, (size_t) (uendp - name));
  591.             get_hdir(unamebuf, localbuf);
  592.             name = uendp;
  593.         }
  594. #endif
  595.     }
  596. #ifndef MSDOS
  597.     else if (*name == '\\')
  598.         name += 1;
  599. #endif /* MSDOS */
  600.     (void) strcat(localbuf, name);
  601.     dfollow(localbuf, intobuf);
  602. }
  603.  
  604. void
  605. filemunge(newname)
  606. char    *newname;
  607. {
  608.     struct stat    stbuf;
  609.  
  610.     if (newname == 0)
  611.         return;
  612.     if (stat(newname, &stbuf))
  613.         return;
  614. #ifndef MSDOS
  615.     if (((stbuf.st_dev != curbuf->b_dev) ||
  616.          (stbuf.st_ino != curbuf->b_ino)) &&
  617. #else /* MSDOS */
  618.     if ( /* (stbuf.st_ino != curbuf->b_ino) && */
  619. #endif /* MSDOS */
  620. #ifndef MAC
  621.         ((stbuf.st_mode & S_IFMT) != S_IFCHR) &&
  622. #endif
  623.         (curbuf->b_fname==NIL || strcmp(newname, curbuf->b_fname) != 0)) {
  624.         rbell();
  625.         confirm("\"%s\" already exists; overwrite it? ", newname);
  626.     }
  627. }
  628.  
  629. void
  630. WrtReg()
  631. {
  632.     DoWriteReg(NO);
  633. }
  634.  
  635. void
  636. AppReg()
  637. {
  638.     DoWriteReg(YES);
  639. }
  640.  
  641. int    CreatMode = DFLT_MODE;
  642.  
  643. private void
  644. DoWriteReg(app)
  645. int    app;
  646. {
  647.     char    fnamebuf[FILESIZE],
  648.         *fname;
  649.     Mark    *mp = CurMark();
  650.     File    *fp;
  651.  
  652.     /* Won't get here if there isn't a Mark */
  653.     fname = ask_file((char *) 0, (char *) 0, fnamebuf);
  654.  
  655. #ifdef BACKUPFILES
  656.     if (app == NO) {
  657.         filemunge(fname);
  658.  
  659.         if (BkupOnWrite)
  660.             file_backup(fname);
  661.     }
  662. #else
  663.     if (!app)
  664.         filemunge(fname);
  665. #endif
  666.  
  667.     fp = open_file(fname, iobuff, app ? F_APPEND : F_WRITE, YES, NO);
  668.     putreg(fp, mp->m_line, mp->m_char, curline, curchar, YES);
  669.     close_file(fp);
  670. }
  671.  
  672. int    OkayBadChars = 0;
  673.  
  674. void
  675. WriteFile()
  676. {
  677.     char    *fname,
  678.         fnamebuf[FILESIZE];
  679. #ifdef MAC
  680.     if (Macmode) {
  681.         if(!(fname = pfile(fnamebuf))) return;
  682.     }
  683.     else
  684. #endif /* MAC */
  685.  
  686.     fname = ask_file((char *) 0, curbuf->b_fname, fnamebuf);
  687.     /* Don't allow bad characters when creating new files. */
  688.     if (!OkayBadChars
  689.     && (curbuf->b_fname==NIL || strcmp(curbuf->b_fname, fnamebuf) != 0))
  690.     {
  691. #ifdef UNIX
  692.         static char    *badchars = "!$^&*()~`{}\"'\\|<>? ";
  693. #endif /* UNIX */
  694. #ifdef MSDOS
  695.         static char    *badchars = "*|<>? ";
  696. #endif /* MSDOS */
  697. #ifdef MAC
  698.         static char *badchars = ":";
  699. #endif /* MAC */
  700.         register char    *cp = fnamebuf;
  701.         register int    c;
  702.  
  703.         while ((c = *cp++ & CHARMASK) != '\0')    /* avoid sign extension... */
  704.             if (c < ' ' || c == '\177' || strchr(badchars, c))
  705.                 complain("'%p': bad character in filename.", c);
  706.     }
  707.  
  708. #if !defined(MAC) && !defined(MSDOS)
  709.     chk_mtime(curbuf, fname, "write");
  710. #endif
  711.     filemunge(fname);
  712.     curbuf->b_type = B_FILE;      /* in case it wasn't before */
  713.     setfname(curbuf, fname);
  714.     file_write(fname, 0);
  715. }
  716.  
  717. /* Open file FNAME supplying the buffer IO routine with buffer BUF.
  718.    HOW is F_READ, F_WRITE or F_APPEND.  IFBAD == COMPLAIN means that
  719.    if we fail at opening the file, call complain.  LOUDNESS says
  720.    whether or not to print the "reading ..." message on the message
  721.    line.
  722.  
  723.    NOTE:  This opens the pr_name(fname, NO) of fname.  That is, FNAME
  724.       is usually an entire pathname, which can be slow when the
  725.       pathname is long and there are lots of symbolic links along
  726.       the way (which has become very common in my experience).  So,
  727.       this speeds up opens file names in the local directory.  It
  728.       will not speed up things like "../scm/foo.scm" simple because
  729.       by the time we get here that's already been expanded to an
  730.       absolute pathname.  But this is a start.
  731.    */
  732.  
  733. File *
  734. open_file(fname, buf, how, complainifbad, quiet)
  735. register char    *fname;
  736. char    *buf;
  737. register int    how;
  738. int    complainifbad,
  739.     quiet;
  740. {
  741.     register File    *fp;
  742.  
  743.     io_chars = 0;
  744.     io_lines = 0;
  745.  
  746.     fp = f_open(pr_name(fname, NO), how, buf, LBSIZE);
  747.     if (fp == NIL) {
  748.         message(IOerr((how == F_READ) ? "open" : "create", fname));
  749.         if (complainifbad)
  750.             complain((char *) 0);
  751.     } else {
  752.         int    rd_only = FALSE;
  753. #ifndef MAC
  754.         if (access(pr_name(fname, NO), W_OK) == -1 && errno != ENOENT) {
  755.             rd_only = TRUE;
  756.             fp->f_flags |= F_READONLY;
  757.         }
  758. #endif
  759.         if (!quiet) {
  760.             fp->f_flags |= F_TELLALL;
  761.             f_mess("\"%s\"%s", pr_name(fname, YES),
  762.                    rd_only ? " [Read only]" : NullStr);
  763.         }
  764.     }
  765.     return fp;
  766. }
  767.  
  768. #ifndef MSDOS
  769. /* Check to see if the file has been modified since it was
  770.    last written.  If so, make sure they know what they're
  771.    doing.
  772.  
  773.    I hate to use another stat(), but to use confirm we gotta
  774.    do this before we open the file.
  775.  
  776.    NOTE: This stats FNAME after converting it to a path-relative
  777.      name.  I can't see why this would cause a problem ...
  778.    */
  779.  
  780. void
  781. chk_mtime(thisbuf, fname, how)
  782. Buffer    *thisbuf;
  783. char    *fname,
  784.     *how;
  785. {
  786.     struct stat    stbuf;
  787.     Buffer    *b;
  788.     char    *mesg = "Shall I go ahead and %s anyway? ";
  789.  
  790.     if ((thisbuf->b_mtime != 0) &&        /* if we care ... */
  791.         ((b = file_exists(fname)) != NIL) &&        /* we already have this file */
  792.         (b == thisbuf) &&            /* and it's the current buffer */
  793.         (stat(pr_name(fname, NO), &stbuf) != -1) &&    /* and we can stat it */
  794.         (stbuf.st_mtime != b->b_mtime)) {    /* and there's trouble. */
  795.         rbell();
  796.         redisplay();    /* Ring that bell! */
  797.         TOstart("Warning", TRUE);
  798.         Typeout("\"%s\" now saved on disk is not what you last", pr_name(fname, YES));
  799.         Typeout("visited or saved.  Probably someone else is editing");
  800.         Typeout("your file at the same time.");
  801.         if (how) {
  802.             Typeout("");
  803.             Typeout("Type \"y\" if I should %s, anyway.", how);
  804.             f_mess(mesg, how);
  805.         }
  806.         TOstop();
  807.         if (how)
  808.             confirm(mesg, how);
  809.     }
  810. }
  811.  
  812. #endif /* MSDOS */
  813.  
  814. void
  815. file_write(fname, app)
  816. char    *fname;
  817. int    app;
  818. {
  819.     File    *fp;
  820.  
  821. #ifdef BACKUPFILES
  822.     if (!app && BkupOnWrite)
  823.         file_backup(fname);
  824. #endif
  825.  
  826.     fp = open_file(fname, iobuff, app ? F_APPEND : F_WRITE, YES, NO);
  827.  
  828.     if (EndWNewline) {    /* Make sure file ends with a newLine */
  829.         Bufpos    save;
  830.  
  831.         DOTsave(&save);
  832.         ToLast();
  833.         if (length(curline))    /* Not a blank Line */
  834.             LineInsert(1);
  835.         SetDot(&save);
  836.     }
  837.     putreg(fp, curbuf->b_first, 0, curbuf->b_last, length(curbuf->b_last), NO);
  838.     close_file(fp);
  839.     set_ino(curbuf);
  840.     unmodify();
  841. }
  842.  
  843. void
  844. ReadFile()
  845. {
  846.     Buffer    *bp;
  847.     char    *fname,
  848.         fnamebuf[FILESIZE];
  849.     int    lineno;
  850.  
  851. #ifdef MAC
  852.     if(Macmode) {
  853.         if(!(fname = gfile(fnamebuf))) return;
  854.     }
  855.     else
  856. #endif /* MAC */
  857.     fname = ask_file((char *) 0, curbuf->b_fname, fnamebuf);
  858. #if !(defined(MSDOS) || defined(MAC))
  859.     chk_mtime(curbuf, fname, "read");
  860. #endif /* MSDOS || MAC */
  861.  
  862.     if (IsModified(curbuf)) {
  863.         char    *y_or_n;
  864.         int    c;
  865.  
  866.         for (;;) {
  867.             rbell();
  868.             y_or_n = ask(NullStr, "Shall I make your changes to \"%s\" permanent? ", curbuf->b_name);
  869.             c = CharUpcase(*y_or_n);
  870.             if (c == 'Y' || c == 'N')
  871.                 break;
  872.         }
  873.         if (c == 'Y')
  874.             SaveFile();
  875.     }
  876.  
  877.     if ((bp = file_exists(fnamebuf)) != NIL &&
  878.         (bp == curbuf))
  879.         lineno = pnt_line() - 1;
  880.     else
  881.         lineno = 0;
  882.  
  883.     unmodify();
  884.     initlist(curbuf);
  885.     setfname(curbuf, fname);
  886.     read_file(fname, 0);
  887.     SetLine(next_line(curbuf->b_first, lineno));
  888. }
  889.  
  890. void
  891. InsFile()
  892. {
  893.     char    *fname,
  894.         fnamebuf[FILESIZE];
  895. #ifdef MAC
  896.     if(Macmode) {
  897.         if(!(fname = gfile(fnamebuf))) return;
  898.     }
  899.     else
  900. #endif /* MAC */
  901.     fname = ask_file((char *) 0, curbuf->b_fname, fnamebuf);
  902.     read_file(fname, 1);
  903. }
  904.  
  905. #include "temp.h"
  906.  
  907. int    DOLsave = 0;    /* Do Lsave flag.  If lines aren't being saved
  908.                when you think they should have been, this
  909.                flag is probably not being set, or is being
  910.                cleared before lsave() was called. */
  911.  
  912. private int    nleft,    /* number of good characters left in current block */
  913.         tmpfd = -1;
  914. daddr    DFree = 1;  /* pointer to end of tmp file */
  915. private char    *tfname;
  916.  
  917. void
  918. tmpinit()
  919. {
  920.     char    buf[FILESIZE];
  921.  
  922. #ifdef MAC
  923.     swritef(buf, "%s/%s", HomeDir, d_tempfile);
  924. #else
  925.     swritef(buf, "%s/%s", TmpFilePath, d_tempfile);
  926. #endif
  927.     tfname = copystr(buf);
  928.     tfname = mktemp(tfname);
  929.     (void) close(creat(tfname, 0600));
  930. #ifndef MSDOS
  931.     tmpfd = open(tfname, 2);
  932. #else /* MSDOS */
  933.     tmpfd = open(tfname, 0x8002);    /* MSDOS fix    */
  934. #endif /* MSDOS */
  935.     if (tmpfd == -1)
  936.         complain("Warning: cannot create tmp file!");
  937. }
  938.  
  939. void
  940. tmpclose()
  941. {
  942.     if (tmpfd == -1)
  943.         return;
  944.     (void) close(tmpfd);
  945.     tmpfd = -1;
  946.     (void) unlink(tfname);
  947. }
  948.  
  949. /* get a line at `tl' in the tmp file into `buf' which should be LBSIZE
  950.    long */
  951.  
  952. int    Jr_Len;        /* length of Just Read Line */
  953.  
  954. #ifdef MAC    /* The Lighspeed compiler can't copy with static here */
  955.     char    *getblock();
  956. #else
  957. private char    *getblock();
  958. #endif
  959. void
  960. getline(addr, buf)
  961. daddr    addr;
  962. register char    *buf;
  963. {
  964.     register char    *bp,
  965.             *lp;
  966.  
  967.     lp = buf;
  968.     bp = getblock(addr >> 1, READ);
  969.     do ; while ((*lp++ = *bp++) != '\0');
  970.     Jr_Len = (lp - buf) - 1;
  971. }
  972.  
  973. /* Put `buf' and return the disk address */
  974.  
  975. daddr
  976. putline(buf)
  977. char    *buf;
  978. {
  979.     register char    *bp,
  980.             *lp;
  981.     register int    nl;
  982.     daddr    free_ptr;
  983.  
  984.     lp = buf;
  985.     free_ptr = DFree;
  986.     bp = getblock(free_ptr, WRITE);
  987.     nl = nleft;
  988.     free_ptr = blk_round(free_ptr);
  989.     while ((*bp = *lp++) != '\0') {
  990.         if (*bp++ == '\n') {
  991.             *--bp = 0;
  992.             break;
  993.         }
  994.         if (--nl == 0) {
  995.             free_ptr = forward_block(free_ptr);
  996.             DFree = free_ptr;
  997.             bp = getblock(free_ptr, WRITE);
  998.             lp = buf;    /* start over ... */
  999.             nl = nleft;
  1000.         }
  1001.     }
  1002.     free_ptr = DFree;
  1003.     DFree += (((lp - buf) + CH_SIZE - 1) / CH_SIZE);
  1004.          /* (lp - buf) includes the null */
  1005.     return (free_ptr << 1);
  1006. }
  1007.  
  1008. /* The theory is that critical section of code inside this procedure
  1009.    will never cause a problem to occur.  Basically, we need to ensure
  1010.    that two blocks are in memory at the same time, but I think that
  1011.    this can never screw up. */
  1012.  
  1013. #define lockblock(addr)
  1014. #define unlockblock(addr)
  1015.  
  1016. daddr
  1017. f_getputl(line, fp)
  1018. Line    *line;
  1019. register File    *fp;
  1020. {
  1021.     register char    *bp;
  1022.     register int    c,
  1023.             nl,
  1024.             room = LBSIZE;
  1025.     daddr    free_ptr;
  1026.     char        *base;
  1027. #ifdef MSDOS
  1028.     char crleft = 0;
  1029. #endif /* MSDOS */
  1030.  
  1031.     free_ptr = DFree;
  1032.     base = bp = getblock(free_ptr, WRITE);
  1033.     nl = nleft;
  1034.     free_ptr = blk_round(free_ptr);
  1035.     while (--room > 0) {
  1036. #ifdef MSDOS
  1037.         if (crleft) {
  1038.            c = crleft;
  1039.            crleft = 0;
  1040.         } else
  1041. #endif /* MSDOS */
  1042.         c = jgetc(fp);
  1043.         if (c == EOF || c == '\n')
  1044.             break;
  1045. #ifdef MSDOS
  1046.         if (c == '\r')
  1047.             if ((crleft = jgetc(fp)) == '\n') {
  1048.                 crleft = 0;
  1049.                 break;
  1050.             }
  1051. #endif /* MSDOS */
  1052.         if (--nl == 0) {
  1053.             char    *newbp;
  1054.             size_t    nbytes;
  1055.  
  1056.             lockblock(free_ptr);
  1057.             DFree = free_ptr = forward_block(free_ptr);
  1058.             nbytes = bp - base;
  1059.             newbp = getblock(free_ptr, WRITE);
  1060.             nl = nleft;
  1061.             byte_copy(base, newbp, nbytes);
  1062.             bp = newbp + nbytes;
  1063.             base = newbp;
  1064.             unlockblock(free_ptr);
  1065.         }
  1066.         *bp++ = c;
  1067.     }
  1068.     *bp++ = '\0';
  1069.     free_ptr = DFree;
  1070.     DFree += (((bp - base) + CH_SIZE - 1) / CH_SIZE);
  1071.     line->l_dline = (free_ptr << 1);
  1072.     if (room == 0) {
  1073.         add_mess(" [Line too long]");
  1074.         rbell();
  1075.         return EOF;
  1076.     }
  1077.     if (c == EOF) {
  1078.         if (--bp != base)
  1079.             add_mess(" [Incomplete last line]");
  1080.         return EOF;
  1081.     }
  1082.     io_lines += 1;
  1083.     return 0;
  1084. }
  1085.  
  1086. typedef struct block {
  1087.     short    b_dirty,
  1088.         b_bno;
  1089.     char    b_buf[JBUFSIZ];
  1090.     struct block
  1091.         *b_LRUnext,
  1092.         *b_LRUprev,
  1093.         *b_HASHnext;
  1094. } Block;
  1095.  
  1096. #define HASHSIZE    7    /* Primes work best (so I'm told) */
  1097. #define B_HASH(bno)    ((bno) % HASHSIZE)
  1098.  
  1099. #ifdef MAC
  1100. private Block    *b_cache,
  1101. #else
  1102. private Block    b_cache[NBUF],
  1103. #endif
  1104.         *bht[HASHSIZE],        /* Block hash table. Must be zero initially */
  1105.         *f_block = 0,
  1106.         *l_block = 0;
  1107. private int    max_bno = -1,
  1108.         NBlocks;
  1109.  
  1110. #ifdef MAC
  1111. void (*blkio)();
  1112. #else
  1113. private void    (*blkio) proto((Block *, int (*)()));
  1114. #endif /* MAC */
  1115.  
  1116. #ifdef MAC
  1117. make_cache()    /* Only 32K of static space on Mac, so... */
  1118. {
  1119.     return((b_cache = (Block *) calloc(NBUF,sizeof(Block))) == 0 ? 0 : 1);
  1120. }
  1121. #endif /* MAC */
  1122.  
  1123. extern int read(), write();
  1124.  
  1125. private void
  1126. real_blkio(b, iofcn)
  1127. register Block    *b;
  1128. #if defined(MAC) || defined(IBMPC)
  1129. register int     (*iofcn)();
  1130. #else
  1131. register int    (*iofcn) proto((int, UnivPtr, size_t));
  1132. #endif /* MAC */
  1133. {
  1134.     (void) lseek(tmpfd, (long) ((unsigned) b->b_bno) * JBUFSIZ, 0);
  1135.     if ((*iofcn)(tmpfd, b->b_buf, (size_t)JBUFSIZ) != JBUFSIZ)
  1136.         error("[Tmp file %s error; to continue editing would be dangerous]",
  1137.             (iofcn == read) ? "READ" : "WRITE");
  1138. }
  1139.  
  1140. private void
  1141. fake_blkio(b, iofcn)
  1142. register Block    *b;
  1143. register int    (*iofcn)();
  1144. {
  1145.     tmpinit();
  1146.     blkio = real_blkio;
  1147.     real_blkio(b, iofcn);
  1148. }
  1149.  
  1150. void
  1151. d_cache_init()
  1152. {
  1153.     register Block    *bp,    /* Block pointer */
  1154.             **hp;    /* Hash pointer */
  1155.     register short    bno;
  1156.  
  1157.     for (bp = b_cache, bno = NBUF; --bno >= 0; bp++) {
  1158.         NBlocks += 1;
  1159.         bp->b_dirty = 0;
  1160.         bp->b_bno = bno;
  1161.         if (l_block == 0)
  1162.             l_block = bp;
  1163.         bp->b_LRUprev = 0;
  1164.         bp->b_LRUnext = f_block;
  1165.         if (f_block != 0)
  1166.             f_block->b_LRUprev = bp;
  1167.         f_block = bp;
  1168.  
  1169.         bp->b_HASHnext = *(hp = &bht[B_HASH(bno)]);
  1170.         *hp = bp;
  1171.     }
  1172.     blkio = fake_blkio;
  1173. }
  1174.  
  1175. void
  1176. SyncTmp()
  1177. {
  1178.     register Block    *b;
  1179. #ifdef IBMPC
  1180.     register int    bno = 0;
  1181.  
  1182.     /* sync the blocks in order, for file systems that don't allow
  1183.        holes (MSDOS).  Perhaps this benefits floppy-based file systems. */
  1184.  
  1185.     for (bno = 0; bno <= max_bno; ) {
  1186.         if ((b = lookup(bno++)) && b->b_dirty) {
  1187.             (*blkio)(b, write);
  1188.             b->b_dirty = 0;
  1189.         }
  1190.     }
  1191. #else
  1192.     for (b = f_block; b != 0; b = b->b_LRUnext)
  1193.         if (b->b_dirty) {
  1194.             (*blkio)(b, write);
  1195.             b->b_dirty = 0;
  1196.         }
  1197. #endif
  1198. }
  1199.  
  1200. private Block *
  1201. lookup(bno)
  1202. register short    bno;
  1203. {
  1204.     register Block    *bp;
  1205.  
  1206.     for (bp = bht[B_HASH(bno)]; bp != 0; bp = bp->b_HASHnext)
  1207.         if (bp->b_bno == bno)
  1208.             break;
  1209.     return bp;
  1210. }
  1211.  
  1212. private void
  1213. LRUunlink(b)
  1214. register Block    *b;
  1215. {
  1216.     if (b->b_LRUprev == 0)
  1217.         f_block = b->b_LRUnext;
  1218.     else
  1219.         b->b_LRUprev->b_LRUnext = b->b_LRUnext;
  1220.     if (b->b_LRUnext == 0)
  1221.         l_block = b->b_LRUprev;
  1222.     else
  1223.         b->b_LRUnext->b_LRUprev = b->b_LRUprev;
  1224. }
  1225.  
  1226. private Block *
  1227. b_unlink(bp)
  1228. register Block    *bp;
  1229. {
  1230.     register Block    *hp,
  1231.             *prev = 0;
  1232.  
  1233.     LRUunlink(bp);
  1234.     /* Now that we have the block, we remove it from its position
  1235.        in the hash table, so we can THEN put it somewhere else with
  1236.        it's new block assignment. */
  1237.  
  1238.     for (hp = bht[B_HASH(bp->b_bno)]; hp != 0; prev = hp, hp = hp->b_HASHnext)
  1239.         if (hp == bp)
  1240.             break;
  1241.     if (hp == 0) {
  1242.         writef("\rBlock %d missing!", bp->b_bno);
  1243.         finish(0);
  1244.     }
  1245.     if (prev)
  1246.         prev->b_HASHnext = hp->b_HASHnext;
  1247.     else
  1248.         bht[B_HASH(bp->b_bno)] = hp->b_HASHnext;
  1249.  
  1250.     if (bp->b_dirty) {    /* do, now, the delayed write */
  1251.         (*blkio)(bp, write);
  1252.         bp->b_dirty = 0;
  1253.     }
  1254.  
  1255.     return bp;
  1256. }
  1257.  
  1258. /* Get a block which contains at least part of the line with the address
  1259.    atl.  Returns a pointer to the block and sets the global variable
  1260.    nleft (number of good characters left in the buffer). */
  1261.  
  1262. private char *
  1263. getblock(atl, iof)
  1264. daddr    atl;
  1265. int    iof;
  1266. {
  1267.     register int    bno,
  1268.             off;
  1269.     register Block    *bp;
  1270.     static Block    *lastb = 0;
  1271.  
  1272.     bno = da_to_bno(atl);
  1273.     off = da_to_off(atl);
  1274.     if (da_too_huge(atl))
  1275.         error("Tmp file too large.  Get help!");
  1276.     nleft = JBUFSIZ - off;
  1277.     if (lastb != 0 && lastb->b_bno == bno) {
  1278.         lastb->b_dirty |= iof;
  1279.         return lastb->b_buf + off;
  1280.     }
  1281.  
  1282.     /* The requested block already lives in memory, so we move
  1283.        it to the end of the LRU list (making it Most Recently Used)
  1284.        and then return a pointer to it. */
  1285.     if ((bp = lookup(bno)) != NIL) {
  1286.         if (bp != l_block) {
  1287.             LRUunlink(bp);
  1288.             if (l_block == 0)
  1289.                 f_block = l_block = bp;
  1290.             else
  1291.                 l_block->b_LRUnext = bp;
  1292.             bp->b_LRUprev = l_block;
  1293.             l_block = bp;
  1294.             bp->b_LRUnext = 0;
  1295.         }
  1296.         if (bp->b_bno > max_bno)
  1297.             max_bno = bp->b_bno;
  1298.         bp->b_dirty |= iof;
  1299.         lastb = bp;
  1300.         return bp->b_buf + off;
  1301.     }
  1302.  
  1303.     /* The block we want doesn't reside in memory so we take the
  1304.        least recently used clean block (if there is one) and use
  1305.        it.  */
  1306.     bp = f_block;
  1307.     if (bp->b_dirty)    /* The best block is dirty ... */
  1308.         SyncTmp();
  1309.  
  1310.     bp = b_unlink(bp);
  1311.     if (l_block == 0)
  1312.         l_block = f_block = bp;
  1313.     else
  1314.         l_block->b_LRUnext = bp;    /* Place it at the end ... */
  1315.     bp->b_LRUprev = l_block;
  1316.     l_block = bp;
  1317.     bp->b_LRUnext = 0;        /* so it's Most Recently Used */
  1318.  
  1319.     bp->b_dirty = iof;
  1320.     bp->b_bno = bno;
  1321.     bp->b_HASHnext = bht[B_HASH(bno)];
  1322.     bht[B_HASH(bno)] = bp;
  1323.  
  1324.     /* Get the current contents of the block UNLESS this is a new
  1325.        block that's never been looked at before, i.e., it's past
  1326.        the end of the tmp file. */
  1327.  
  1328.     if (bp->b_bno <= max_bno)
  1329.         (*blkio)(bp, read);
  1330.     else
  1331.         max_bno = bno;
  1332.  
  1333.     lastb = bp;
  1334.     return bp->b_buf + off;
  1335. }
  1336.  
  1337. char *
  1338. lbptr(line)
  1339. Line    *line;
  1340. {
  1341.     return getblock(line->l_dline >> 1, READ);
  1342. }
  1343.  
  1344. /* save the current contents of linebuf, if it has changed */
  1345.  
  1346. void
  1347. lsave()
  1348. {
  1349.     if (curbuf == 0 || !DOLsave)    /* Nothing modified recently */
  1350.         return;
  1351.  
  1352.     if (strcmp(lbptr(curline), linebuf) != 0)
  1353.         SavLine(curline, linebuf);    /* Put linebuf on the disk. */
  1354.     DOLsave = 0;
  1355. }
  1356.  
  1357. #ifdef BACKUPFILES
  1358. private void
  1359. file_backup(fname)
  1360. char *fname;
  1361. {
  1362. #ifndef MSDOS
  1363.     char    *s;
  1364.     register int    i;
  1365.     int    fd1,
  1366.         fd2;
  1367.     char    tmp1[JBUFSIZ],
  1368.         tmp2[JBUFSIZ];
  1369.     struct stat buf;
  1370.     int    mode;
  1371.  
  1372.     strcpy(tmp1, fname);
  1373.     if ((s = strrchr(tmp1, '/')) == NULL)
  1374.         swritef(tmp2, "#%s~", fname);
  1375.     else {
  1376.         *s++ = '\0';
  1377.         swritef(tmp2, "%s/#%s~", tmp1, s);
  1378.     }
  1379.  
  1380.     if ((fd1 = open(fname, 0)) < 0)
  1381.         return;
  1382.  
  1383.     /* create backup file with same mode as input file */
  1384. #ifndef MAC
  1385.     if (fstat(fd1, &buf) != 0)
  1386.         mode = CreatMode;
  1387.     else
  1388. #endif
  1389.         mode = buf.st_mode;
  1390.  
  1391.     if ((fd2 = creat(tmp2, mode)) < 0) {
  1392.         (void) close(fd1);
  1393.         return;
  1394.     }
  1395.     while ((i = read(fd1, tmp1, sizeof(tmp1))) > 0)
  1396.         write(fd2, tmp1, (size_t) i);
  1397. #ifdef BSD4_2
  1398.     (void) fsync(fd2);
  1399. #endif
  1400.     (void) close(fd2);
  1401.     (void) close(fd1);
  1402. #else /* MSDOS */
  1403.     char    *dot,
  1404.             *slash,
  1405.             tmp[FILESIZE];
  1406.  
  1407.     strcpy(tmp, fname);
  1408.     slash = basename(tmp);
  1409.     if (dot = strrchr(slash, '.')) {
  1410.        if (!stricmp(dot,".bak"))
  1411.         return;
  1412.        else *dot = 0;
  1413.     }
  1414.     strcat(tmp, ".bak");
  1415.     unlink(tmp);
  1416.     rename(fname, tmp);
  1417. #endif /* MSDOS */
  1418. }
  1419. #endif
  1420.  
  1421. #if defined(MSDOS)
  1422.  
  1423. private int            /* chdir + drive */
  1424. Dchdir(to)
  1425. char *to;
  1426. {
  1427.     unsigned d, dd, n;
  1428.  
  1429.     if (to[1] == ':') {
  1430.         d = to[0];
  1431.         if (d >= 'a') d = d - 'a' + 1;
  1432.         if (d >= 'A') d = d - 'A' + 1;
  1433.         _dos_getdrive(&dd);
  1434.         if (dd != d)
  1435.             _dos_setdrive(d, &n);
  1436.         if (to[2] == 0)
  1437.             return 0;
  1438.     }
  1439.     return chdir(to);
  1440. }
  1441.  
  1442. private char *
  1443. fixpath(p)
  1444. char *p;
  1445. {
  1446.     char *pp = p;
  1447.  
  1448.     while (*p) {
  1449.         if (*p == '\\')
  1450.             *p = '/';
  1451.         p++;
  1452.     }
  1453.     return(strlwr(pp));
  1454. }
  1455.  
  1456.  
  1457. private void
  1458. abspath(so, dest)
  1459. char *so, *dest;
  1460. {
  1461.     char cwd[FILESIZE], cwdD[3], cwdDIR[FILESIZE], cwdF[9], cwdEXT[5],
  1462.          soD[3], soDIR[FILESIZE], soF[9], soEXT[5];
  1463.     char *drive, *path;
  1464.  
  1465.     _splitpath(fixpath(so), soD, soDIR, soF, soEXT);
  1466.     getcwd(cwd, FILESIZE);
  1467.     if (*soD != 0) {
  1468.         Dchdir(soD);                /* this is kinda messy    */
  1469.         getcwd(cwdDIR, FILESIZE);    /* should probably just    */
  1470.         Dchdir(cwd);                /* call DOS to do it    */
  1471.         strcpy(cwd, cwdDIR);
  1472.     }
  1473.     (void) fixpath(cwd);
  1474.     if (cwd[strlen(cwd)-1] != '/')
  1475.         strcat(cwd, "/x.x");    /* need dummy filename */
  1476.  
  1477.     _splitpath(fixpath(cwd), cwdD, cwdDIR, cwdF, cwdEXT);
  1478.  
  1479.     drive = (*soD == 0) ? cwdD : soD;
  1480.  
  1481.     if (*soDIR != '/')
  1482.         path = strcat(cwdDIR, soDIR);
  1483.     else
  1484.         path = soDIR;
  1485.     _makepath(dest, drive, path, soF, soEXT);
  1486.     fixpath(dest);    /* can't do it often enough */
  1487. }
  1488.  
  1489. #endif
  1490.